package com.beantools.reflect.property;

import com.beantools.entity.EntityStorage;
import com.beantools.entity.enums.DateFormatEnum;
import com.beantools.execption.InformationException;
import com.beantools.execption.PropertyException;
import com.beantools.factory.reflect.CommonReflectFactory;
import com.beantools.factory.verify.StorageVerifyFactory;
import com.beantools.util.ArrayUtil;
import com.beantools.util.JavaTypeUtil;

import java.io.Serializable;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.*;

import static com.beantools.constants.FrameConstant.ROOT_CLASS_OBJECT;
import static com.beantools.constants.MethodPrefix.PREFIX_GET;
import static com.beantools.constants.MethodPrefix.PREFIX_SET;
import static com.beantools.constants.SingleChar.*;
import static com.beantools.util.ObjectUtil.isNotNull;
import static com.beantools.util.ObjectUtil.isNull;
import static com.beantools.util.StringUtil.isBlank;
import static com.beantools.util.StringUtil.isEmpty;
import static java.math.BigDecimal.*;

/**
 * 这是属性类，根据对象属性的名称获取对象属性值。经过简单的封装之后，
 * 可以根据属性名封装到{@code map}当中。{@code key}值是对象属性名，
 * {@code value}值为对象属性值
 *
 * @author baoya
 * @version 1.1.0
 * @Documented
 * @since 1.0
 */
public class Property implements Serializable {

    private static final long serialVersionUID = 1918835888535043910L;

    /**
     * 这是实例化的对象
     */
    private Object object;

    /**
     * 这是存储对象的tokens
     */
    private List<Object> tokens = new LinkedList<>();
    /**
     * 这里用的验证工厂类，随后会指向属性验证工厂类
     */
    private StorageVerifyFactory verifyFactory;

    private Property(Object object) {
        if (isNull(object)) {
            throw new IllegalArgumentException("对象不能为空");
        }
        this.object = object;
        tokens.removeAll(tokens);
        verifyFactory = StorageVerifyFactory.getInstance(object.getClass());
    }

    private Property() {
        tokens.removeAll(tokens);
        verifyFactory = StorageVerifyFactory.getInstance();
    }

    public static Property getInstance() {
        return new Property();
    }

    public static Property getInstance(Object object) {
        return new Property(object);
    }

    /**
     * 根据属性名获取属性值。这个方法可以直接通过属性名获取属性值。
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Object getProperty(String propertyName) {
        return getProperty(propertyName, this.object);
    }

    /**
     * 根据属性名获取属性值，如果其实字符串类型，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public String getString(String propertyName, Object obj) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoString(property);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其是整形类型，可以将其转化为整形或整形对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Integer getInteger(String propertyName, Object obj) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoInt(property);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其是长整形，可以将其转化为长整形湖长整形对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Long getLong(String propertyName, Object obj) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoLong(property);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @param decimals     小数位数
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Double getDouble(String propertyName, Object obj, Integer decimals, Integer round) {
        try {
            Object property = getProperty(propertyName, obj);
            Double var = JavaTypeUtil.transformIntoDouble(property);
            if (isNull(var)) {
                return var;
            }
            decimals = isNull(decimals) ? ROUND_CEILING : decimals;
            round = isNull(round) ? ROUND_HALF_UP : round;
            validParam(decimals, round);
            return new BigDecimal(var).setScale(decimals, round).doubleValue();
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public float getFloat(String propertyName, Object obj, Integer decimals, Integer round) {
        try {
            Object property = getProperty(propertyName, obj);
            Float var = JavaTypeUtil.transformIntoFloat(property);
            if (isNull(var)) {
                return var;
            }
            decimals = isNull(decimals) ? ROUND_CEILING : decimals;
            round = isNull(round) ? ROUND_HALF_UP : round;
            validParam(decimals, round);
            return new BigDecimal(var).setScale(decimals, round).floatValue();
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * Created By zby on 21:48 2019/6/16
     * 验证参数
     *
     * @param decimals 小数位
     * @param round    采用哪种舍入方法
     */
    private void validParam(int decimals, int round) {
        if (decimals <= ROUND_UP) {
            throw new IllegalArgumentException("小数位必须大于0");
        }
        if (round < ROUND_UP || round > ROUND_UNNECESSARY) {
            throw new IllegalArgumentException("round必须在0到7之间");
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Short getShort(String propertyName, Object obj) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoShort(property);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Byte getByte(String propertyName, Object obj) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoByte(property);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Character getChar(String propertyName, Object obj) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoChar(property);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public BigDecimal getBigDecimal(String propertyName, Object obj, int decimals, int round) {
        try {
            Object property = getProperty(propertyName, obj);
            BigDecimal var = JavaTypeUtil.transformIntoBigDecimal(property);
            if (isNull(var)) {
                return var;
            }
            decimals = isNull(decimals) ? ROUND_CEILING : decimals;
            round = isNull(round) ? ROUND_HALF_UP : round;
            validParam(decimals, round);
            return var.setScale(decimals, round);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }


    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public BigInteger getBigInteger(String propertyName, Object obj) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoBigInteger(property);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Date getDate(String propertyName, Object obj, DateFormatEnum dateFormatEnum) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoDate(property, dateFormatEnum);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Date getDate(String propertyName, Object obj, String dateFormat) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoDate(property, dateFormat);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Date getSqlDate(String propertyName, Object obj, String dateFormat) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoDate(property, dateFormat);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Date getSqlDate(String propertyName, Object obj, DateFormatEnum dateFormatEnum) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoDate(property, dateFormatEnum);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Timestamp getTimestamp(String propertyName, Object obj) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoTimestamp(property);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public byte[] getBytes(String propertyName, Object obj) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoBytes(property);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Boolean getBoolean(String propertyName, Object obj) {
        try {
            Object property = getProperty(propertyName, obj);
            return JavaTypeUtil.transformIntoBoolean(property);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值，如果其实整形，可以将其转化为字符串对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public <T> T getEnum(String propertyName, Object obj) {
        try {
            Object property = getProperty(propertyName, obj);
            return (T) JavaTypeUtil.transformIntoEnum(property);
        } catch (PropertyException e) {
            throw new PropertyException(e.getMessage(), propertyName);
        }
    }

    /**
     * 根据属性名获取属性值。
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Object getProperty(String propertyName, Object obj) {
        boolean ObjOfString = isEmpty(propertyName) || isNull(obj) || (obj instanceof String) && (isEmpty((String) obj));
        if (ObjOfString) {
            throw new IllegalArgumentException("参数不能有空值");
        }
        propertyName = propertyName.replaceAll(BLANK_OP, NULL_OP);
        Class persistClass = obj.getClass();
        EntityStorage storage = verifyFactory.getStorageEntity(obj, persistClass, propertyName, PREFIX_GET);
        if (storage == null) {
            return null;
        }
        return getObject(storage.getClazz(), storage);
    }

    /**
     * 这是根据属性名和对应的数据值来填充当前对象的属性值或其关联的属性值。
     * 用户在调用该方法并传递实参时，需要保存<code>clazz</code>的有默认的
     * 构造函数，否则，就会报错
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param clazz        某个实例化的类
     * @param value        填充值
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Object setProperty(String propertyName, Object value, Class clazz) {
        Object object = null;
        if (isNull(clazz)) {
            return object;
        }
        try {
            Constructor defaultConstruct = CommonReflectFactory.getInstance(clazz).getNoArgsConstruct(null);
            object = defaultConstruct.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return setProperty(propertyName, value, object);
    }

    /**
     * 这是根据属性名和对应的数据值来填充当前对象的属性值或其关联的属性值。
     * 但是，调用者在使用该方法前，需要创建初始化当前对象
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param value        填充值
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Object setProperty(String propertyName, Object value) {
        return setProperty(propertyName, value, this.object);
    }

    /**
     * 这是根据属性名和对应的数据值来填充当前对象的属性值或其关联的属性值。
     * <p>
     * 比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     * <p>
     * 如果有{@code Course}的课程类，其有有属性为{@code student}
     * 可以通过getProperty("student.name",student)
     *
     * @param obj          当前对象
     * @param value        填充值
     * @param propertyName 对象的属性名称
     * @return 如果存在属性值，就返回属性值，否则，返回空
     */
    public Object setProperty(String propertyName, Object value, Object obj) {
        Object var = isNull(obj) ? this.object : obj;
        String tmpName;
        if (isBlank(propertyName)) {
            throw new InformationException("对象属性名称不能为空");
        }
        if (isNull(var)) {
            throw new InformationException("对象名称不能为空");
        }
        tokens.add(var);
        var = tokens.get(tokens.size() - ROUND_DOWN);
        Class persistClass = var.getClass();
//        处理当前对象所关联的类
        try {
            if (propertyName.indexOf(EN_POINT) != -1) {
                tmpName = propertyName.substring(0, propertyName.indexOf(EN_POINT));
                EntityStorage storage = verifyFactory.storeEntity(persistClass, tmpName, PREFIX_SET);
                Object tmpObj = getProperty(tmpName, var);
                tmpName = propertyName.substring(propertyName.indexOf(EN_POINT) + 1);
                if (isNull(tmpObj)) {
                    Parameter[] parameters = storage.getMethod().getParameters();
                    if (ArrayUtil.isEmpty(parameters) || parameters.length > 1) {
                        throw new PropertyException("参数异常", tmpName, persistClass);
                    }
                    Class clazz = parameters[0].getType();
                    Constructor defaultConstruct = CommonReflectFactory.getInstance(clazz).getNoArgsConstruct(null);
                    tmpObj = defaultConstruct.newInstance();
                    storage.getMethod().invoke(var, tmpObj);
                    return setProperty(tmpName, value, tmpObj);
                }
                return setProperty(tmpName, value, tmpObj);
            }
            EntityStorage storage = verifyFactory.storeEntity(persistClass, propertyName, PREFIX_SET);
            Object result = storage.getMethod().invoke(obj, value);
            if (isNull(result)) {
                return tokens.get(0);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将这种格式的name/baoya数据封装成list集
     *
     * @param propertyName 属性名称,
     * @param object       当前类对象
     * @return 返回的是{@code List}的容器
     */
    protected List getNameValues(String propertyName, Object object) {
        Map<String, Object> nameAndValue = getNameAndValue(propertyName, object);
        if (isNull(nameAndValue)) {
            return null;
        }
        if (nameAndValue.isEmpty() || nameAndValue.size() >= ROUND_CEILING) {
            throw new NullPointerException("类" + object.getClass().getName() +
                    "的属性" + propertyName + "封装异常");
        }
        List<Object> nameValueList = new LinkedList();
        for (Map.Entry<String, Object> entry : nameAndValue.entrySet()) {
            nameValueList.add(entry.getKey());
            nameValueList.add(entry.getValue());
        }
        return nameValueList;
    }

    /**
     * 调用者将获取到的属性对象封装成JsonObject对象，如果你想了解更多有关fastjson框架的知识
     * 可以参考这个链接<a href="http://www.runoob.com/w3cnote/fastjson-intro.html">fastjson</a>
     * <p>
     * 如果你的{@code object}的是{@code Course}类的实例化对象，该类关联{@code  Student}类，
     * 但是想要获取的{@code Student}对象的的{@code name}值，你可以这样写：
     * <code>
     * <pre>  propertyName="student.name:studentName"  </pre>
     * </code>
     * {@code studentName}是别名，也就是，你需要展示给前台的名称
     *
     * 如果你的{@code object}是{@code Student}类的实例化对象，你想要获取其{@code name}的属性值，
     * 你可以这样写：
     * <code>
     * <pre>   propertyName="name"   </pre>
     * </code>
     *
     * @param propertyName 属性名称,
     * @param object       当前类对象
     * @return 如果属性名称存在，值也存在，其返回格式为 name/baoya
     */
    private Map<String, Object> getNameAndValue(String propertyName, Object object) {
        if (isBlank(propertyName)) {
            throw new IllegalArgumentException("属性名称为空");
        }
        propertyName = propertyName.replaceAll(BLANK_OP, NULL_OP);
        if (propertyName.contains(EN_POINT) && !propertyName.contains(SIGN_COLON_OP)) {
            throw new IllegalArgumentException("对象" + object.getClass().getSimpleName() + "如果包含点符号，但必须填写别名，比如student.name:studentName");
        }
//        如果是student.name:studentName，则分隔数组
        String[] propertyNames = propertyName.split(SIGN_COLON_OP);
        if (propertyNames.length >= BigDecimal.ROUND_FLOOR) {
            throw new IllegalArgumentException("不能包含多个冒号分隔符");
        }
        Map<String, Object> nameValueMap = new LinkedHashMap<>();
        if (propertyNames.length == ROUND_DOWN) {
            Object value = isNotNull(object) ? getProperty(propertyNames[ROUND_UP], object) : null;
            nameValueMap.put(propertyNames[ROUND_UP], value);
        }
        if (propertyNames.length == ROUND_CEILING) {
            Object value = isNotNull(object) ? getProperty(propertyNames[ROUND_UP], object) : null;
            nameValueMap.put(propertyNames[ROUND_DOWN], value);
        }
        return nameValueMap;
    }


    /**
     * 这是处理单个属性的方法，比如在{@code Student}类中，有个名为{@code name}的属性，
     * 可以通过getProperty("name",student)获取属性{@code name}值
     *
     * @param clazz   实体类信息
     * @param storage 实体类存储器
     * @return 返回对象的属性值
     */
    private Object getObject(Class clazz, EntityStorage storage) {
        try {
            if (isNull(storage)) {
                return null;
            }
            Method method = getMethod(clazz, storage);
            if (isNull(method)) {
                throw new NullPointerException("当前类和其父类都不存在该属性" + storage.getPropertyName());
            }
            return method.invoke(storage.getObject());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 这是用来创建方法对象的方法。如果实体类中不存在某个属性，那么，
     * 就去查找其父类的属性。如果父类属性也没有，那么，就返回为空
     *
     * @param clazz   类对象，可以是当前类对象，也可以是其父类类对象
     * @param storage 属性对象
     */
    private Method getMethod(Class clazz, EntityStorage storage) {
        String propName = storage.getPropertyName();
        if (isEmpty(propName)) {
            return null;
        }
        Field[] declaredFields = clazz.getDeclaredFields();
        if (ArrayUtil.isNoNullObject(declaredFields)) {
            for (Field declaredField : declaredFields) {
                String fieldName = declaredField.getName();
                if (propName.equals(fieldName)) {
                    return storage.getMethod();
                }
            }
        }
        clazz = clazz.getSuperclass();
        if (isNotNull(clazz) || !ROOT_CLASS_OBJECT.equals(clazz.getSimpleName())) {
            return getMethod(clazz, storage);
        }
        return null;
    }
}
